# core/chatroom_state.py
# Manages the public chat history, participant list and status, whiteboard content, and global tags.
# Detailed implementation will follow based on design documents.

from typing import List, Dict, Optional
from datetime import datetime, timezone # Added for _update_global_tags timestamp
from core.data_models import ChatMessage, ParticipantConfig, WhiteboardItem, GlobalTag
from services.db_service import DBService # To interact with the database

class ChatroomState:
    def __init__(self, db_service: DBService):
        self.db_service = db_service
        
        self.public_chat_history: List[ChatMessage] = []
        self.participants: Dict[str, ParticipantConfig] = {} # participant_id -> ParticipantConfig
        self.participant_runtime_status: Dict[str, Dict] = {} # participant_id -> {"desire_to_speak": False, "is_typing": False}
        self.whiteboard_items: List[WhiteboardItem] = []
        self.global_tags: Dict[str, GlobalTag] = {} # normalized_tag_name -> GlobalTag

        self._load_initial_state()
        print(f"ChatroomState initialized. Loaded {len(self.participants)} participants.")

    def _load_initial_state(self):
        """Loads initial state from the database."""
        print("ChatroomState: Loading initial state from DB...")
        
        # Load participants
        all_participant_configs = self.db_service.get_all_participant_configs()
        for config in all_participant_configs:
            self.participants[config.participant_id] = config
            self.participant_runtime_status[config.participant_id] = {"desire_to_speak": False, "is_typing": False}
        
        # Load recent chat history
        self.public_chat_history = self.db_service.get_recent_chat_messages(limit=100) # Load last 100 messages
        print(f"  Loaded {len(self.public_chat_history)} recent chat messages.")

        # Load whiteboard items
        self.whiteboard_items = self.db_service.get_all_whiteboard_items()
        print(f"  Loaded {len(self.whiteboard_items)} whiteboard items.")

        # Load global tags
        all_global_tags_from_db = self.db_service.get_all_global_tags()
        for tag_obj in all_global_tags_from_db:
            self.global_tags[tag_obj.tag_name] = tag_obj
        print(f"  Loaded {len(self.global_tags)} global tags.")
        print("ChatroomState: Initial state loading complete (participants, chat history, whiteboard items, and global tags loaded).")

    def add_chat_message(self, message: ChatMessage):
        """
        Adds a new chat message to the in-memory history.
        Persistence and global tag updates are handled by the calling service (e.g., InternalApiLogic).
        """
        self.public_chat_history.append(message)
        # self.db_service.add_chat_message(message) # DB persistence handled by InternalApiLogic
        print(f"ChatroomState: Added message {message.message_id} from {message.sender_nickname} to in-memory state.")
        
        # if message.tags:
            # self._update_global_tags(message.tags, message.timestamp) # Global tag updates (DB & memory) handled by InternalApiLogic

    def get_participant_by_id(self, participant_id: str) -> Optional[ParticipantConfig]:
        return self.participants.get(participant_id)

    def update_participant_runtime_status(self, participant_id: str, status_key: str, status_value: bool):
        """Updates runtime status like 'desire_to_speak' or 'is_typing'."""
        if participant_id in self.participant_runtime_status:
            self.participant_runtime_status[participant_id][status_key] = status_value
            print(f"ChatroomState: Participant {participant_id} status '{status_key}' updated to {status_value}.")
        else:
            print(f"Warning: Attempted to update status for unknown participant {participant_id}.")
            
    def get_participant_runtime_status(self, participant_id: str) -> Optional[Dict]:
        return self.participant_runtime_status.get(participant_id)
        
    def get_recent_messages(self, count: int = 10) -> List[ChatMessage]:
        """Returns the most recent chat messages, with newest messages last."""
        if count >= len(self.public_chat_history):
            return self.public_chat_history
        else:
            return self.public_chat_history[-count:]

    def add_whiteboard_item(self, item: WhiteboardItem):
        """
        Adds a new whiteboard item to the in-memory list.
        Persistence is handled by the calling service (e.g., InternalApiLogic).
        """
        # self.db_service.add_whiteboard_item(item) # DB persistence handled by InternalApiLogic
        self.whiteboard_items.append(item)
        print(f"ChatroomState: Added whiteboard item '{item.reference_id}' ({item.display_name}) to in-memory state.")
        # Error handling for DB would be in InternalApiLogic. If that fails, InternalApiLogic might not call this.

    def remove_whiteboard_item(self, reference_id: str) -> bool:
        """
        Removes a whiteboard item from the in-memory list by its reference_id.
        Persistence is handled by the calling service (e.g., InternalApiLogic).
        Returns True if the item was found and removed from memory, False otherwise.
        """
        # db_success = self.db_service.remove_whiteboard_item(reference_id) # DB persistence handled by InternalApiLogic
        
        initial_len = len(self.whiteboard_items)
        self.whiteboard_items = [item for item in self.whiteboard_items if item.reference_id != reference_id]
        removed_from_memory = len(self.whiteboard_items) < initial_len
        
        if removed_from_memory:
            print(f"ChatroomState: Removed whiteboard item '{reference_id}' from in-memory state.")
        else:
            print(f"ChatroomState: Whiteboard item '{reference_id}' not found in in-memory state for removal.")
        return removed_from_memory
    
    def _normalize_tag(self, tag: str) -> str: # This helper can still be useful if InternalApiLogic needs it
        """Normalizes a tag (e.g., lowercase, strip whitespace)."""
        return tag.lower().strip()

    # _update_global_tags method is removed as InternalApiLogic now handles DB and memory updates for global tags.
    # If ChatroomState needed to do purely in-memory tag aggregation based on messages it sees,
    # a different method could be implemented, but current design has InternalApiLogic manage this.

if __name__ == '__main__':
    # This example requires a DBService instance and a populated DB for full effect.
    # We'll simulate parts of it.
    
    print("--- ChatroomState Test ---")
    # Create a dummy DBService and populate it for testing
    from services.db_service import DB_NAME
    import os
    
    test_db_name = "test_chatroom_state.db"
    if os.path.exists(test_db_name):
        os.remove(test_db_name) # Clean start for test

    db_service_instance = DBService(db_name=test_db_name)
    db_service_instance.connect()
    db_service_instance.create_tables_if_not_exist()

    # Add some dummy participant configs
    p_human = ParticipantConfig(participant_id="human1", nickname="Tester", role="human", is_mvp_host=True)
    p_agent = ParticipantConfig(participant_id="agent1", nickname="Botty", role="llm_agent",
                                llm_persona_prompt="You are Botty.",
                                llm_config_listening={"model":"test"}, llm_config_speaking={"model":"test"})
    db_service_instance.add_or_update_participant_config(p_human)
    db_service_instance.add_or_update_participant_config(p_agent)
    
    # Initialize ChatroomState
    chatroom_state = ChatroomState(db_service=db_service_instance)
    
    print(f"\nInitial participants in state: {list(chatroom_state.participants.keys())}")
    print(f"Initial chat history length from DB: {len(chatroom_state.public_chat_history)}")
    print(f"Initial global tags loaded: {list(chatroom_state.global_tags.keys())}")
    print(f"Initial whiteboard items loaded: {len(chatroom_state.whiteboard_items)}") # Added for whiteboard
    
    # Test adding a message
    import uuid
    # from datetime import datetime, timedelta # Already imported if running full file
    
    # Add a new message through ChatroomState
    new_message_content = "A new message added via ChatroomState with new tags!"
    current_time = datetime.now(timezone.utc)
    new_tags = ["Live_Test ", " CHATROOM_STATE ", " unique_tag1 "] # Test normalization
    
    test_message_cs = ChatMessage(
        message_id=str(uuid.uuid4()),
        participant_id="human1",
        sender_nickname="TesterCS",
        content=new_message_content,
        timestamp=current_time,
        tags=new_tags
    )
    chatroom_state.add_chat_message(test_message_cs)
    
    print(f"\nChat history count in state after adding: {len(chatroom_state.public_chat_history)}")
    if chatroom_state.public_chat_history:
        print(f"Last message content in state: '{chatroom_state.public_chat_history[-1].content}'")

    print("\nGlobal tags in state after message:")
    for tag_name, tag_obj in chatroom_state.global_tags.items():
        print(f"  Tag: {tag_name}, Count: {tag_obj.occurrence_count}, Last Seen: {tag_obj.last_seen_timestamp}")
    
    # Verify normalized tags are present
    assert "live_test" in chatroom_state.global_tags
    assert "chatroom_state" in chatroom_state.global_tags
    assert "unique_tag1" in chatroom_state.global_tags
    if "live_test" in chatroom_state.global_tags:
         assert chatroom_state.global_tags["live_test"].occurrence_count >= 1


    # Verify message persistence and tag update by reloading state
    print("\nVerifying message and tag persistence by reloading state...")
    reloaded_chatroom_state = ChatroomState(db_service=db_service_instance)
    print(f"Chat history count in reloaded state: {len(reloaded_chatroom_state.public_chat_history)}")
    
    found_new_message_in_reloaded_state = False
    if reloaded_chatroom_state.public_chat_history:
        print(f"Last message in reloaded state: '{reloaded_chatroom_state.public_chat_history[-1].content}'")
        for msg in reloaded_chatroom_state.public_chat_history:
            if msg.message_id == test_message_cs.message_id:
                found_new_message_in_reloaded_state = True
                break
    print(f"Was the new message found in reloaded state? {found_new_message_in_reloaded_state}")
    assert found_new_message_in_reloaded_state

    print("Global tags in reloaded state:")
    for tag_name, tag_obj in reloaded_chatroom_state.global_tags.items():
        print(f"  Tag: {tag_name}, Count: {tag_obj.occurrence_count}, Last Seen: {tag_obj.last_seen_timestamp}")
    assert "live_test" in reloaded_chatroom_state.global_tags
    if "live_test" in reloaded_chatroom_state.global_tags:
        assert reloaded_chatroom_state.global_tags["live_test"].occurrence_count >= 1


    # --- Test Whiteboard Items ---
    print("\n--- Testing Whiteboard Items ---")
    # Create some dummy whiteboard items
    wb_item1_id = str(uuid.uuid4())
    wb_item1 = WhiteboardItem(
        reference_id=wb_item1_id,
        item_type="file_path",
        full_local_path="/test/path/file1.txt",
        display_name="File 1",
        content_preview="This is file 1.",
        tags=["whiteboard_test", "file"],
        added_by_participant_id="human1",
        added_timestamp=datetime.now(timezone.utc)
    )
    wb_item2_id = str(uuid.uuid4())
    wb_item2 = WhiteboardItem(
        reference_id=wb_item2_id,
        item_type="note",
        content_preview="This is a test note.",
        tags=["whiteboard_test", "note"],
        added_by_participant_id="agent1",
        added_timestamp=datetime.now(timezone.utc)
    )

    # Add whiteboard items
    chatroom_state.add_whiteboard_item(wb_item1)
    chatroom_state.add_whiteboard_item(wb_item2)

    print(f"Whiteboard items in state after adding: {len(chatroom_state.whiteboard_items)}")
    assert len(chatroom_state.whiteboard_items) == 2
    
    # Verify in DB by reloading (or direct query if preferred for a more isolated test)
    reloaded_wb_items_from_db = db_service_instance.get_all_whiteboard_items()
    print(f"Whiteboard items in DB after adding: {len(reloaded_wb_items_from_db)}")
    assert len(reloaded_wb_items_from_db) == 2
    
    found_item1_in_db = any(item.reference_id == wb_item1_id for item in reloaded_wb_items_from_db)
    found_item2_in_db = any(item.reference_id == wb_item2_id for item in reloaded_wb_items_from_db)
    assert found_item1_in_db
    assert found_item2_in_db

    # Test removing a whiteboard item
    remove_result = chatroom_state.remove_whiteboard_item(wb_item1_id)
    print(f"Removal result for item1: {remove_result}")
    assert remove_result
    print(f"Whiteboard items in state after removing item1: {len(chatroom_state.whiteboard_items)}")
    assert len(chatroom_state.whiteboard_items) == 1
    assert chatroom_state.whiteboard_items[0].reference_id == wb_item2_id

    # Verify removal in DB
    reloaded_wb_items_from_db_after_remove = db_service_instance.get_all_whiteboard_items()
    print(f"Whiteboard items in DB after removing item1: {len(reloaded_wb_items_from_db_after_remove)}")
    assert len(reloaded_wb_items_from_db_after_remove) == 1
    assert reloaded_wb_items_from_db_after_remove[0].reference_id == wb_item2_id

    # Test removing a non-existent item
    remove_non_existent_result = chatroom_state.remove_whiteboard_item(str(uuid.uuid4()))
    print(f"Removal result for non-existent item: {remove_non_existent_result}")
    assert not remove_non_existent_result
    assert len(chatroom_state.whiteboard_items) == 1 # Should not have changed

    print("--- Whiteboard Items Test Complete ---")

    # Test updating participant status
    chatroom_state.update_participant_runtime_status("agent1", "desire_to_speak", True) # agent1 from setup
    agent1_status = chatroom_state.get_participant_runtime_status("agent1")
    print(f"Agent1 status: {agent1_status}")

    retrieved_p = chatroom_state.get_participant_by_id("agent1")
    if retrieved_p:
        print(f"Retrieved participant: {retrieved_p.nickname}")

    db_service_instance.close()
    if os.path.exists(test_db_name):
        os.remove(test_db_name) # Clean up test DB
    
    print("\nChatroomState test complete.")